prompt.bash

#!/usr/bin/env bash

# @TODO Add a prompt function that allows you to type the command name OR the number
    # Something like: bent show: 1. history, 2. history full, 3. url
        # Then you can type 1,2, or 3. OR you can type history, history full, or url

function prompt(){
    # @TODO Integrate exiting by default so you'd just write `prompt "msg" arg || return` 
		# & Take a flag to disable printing of exit status
	# @TODO fix output... When going to line 2, it just wraps back to the first line, clearing the prompt message
    read -e -p "$(msg -n "${cCommand}${1}${cOff}") " ${2}
}

# Prompts a user & checks if user aborted the prompt
# Usage: prompt_quit "A MESSAGE" usersAnswer -e && return
# By default an empty message means QUIT=true
# -e is optional & indicates EMPTY message means QUIT=false
# where QUIT is the return value
function prompt_quit(){
    local -n OUTPUT=$2
    read -e -p "$(msg -n "${cCommand}${1}${cOff}${cInstruct} (q-quit)${cOff}") " OUTPUT
    if [[ "$3" == "-e" && -z "$OUTPUT" ]];then
        return 1
    fi
    prompt_exited "$OUTPUT" -p \
        || return 1;
    return 0
}
function prompt_yes_or_quit(){
    read -e -p "$(msg -n "${cCommand}${1}${cOff}${cInstruct} (y/no)${cOff}") " ANSWER
    if [[ "$ANSWER" == "y" || "$ANSWER" == "Y" || "$ANSWER" == "yes" ]];then
        return 1;
    else
        msg_status "'y' required. Exiting"
        return 0;
    fi
}

function prompt_yes_or_no(){
    local answer;
    prompt "$1 (y-yes/n-no): " response
    yesFunc=$2;
    noFunc=$3;
    if [[ $response == "y" || $response == "Y" ]]; then
        return 0
    elif [[ $response == "n" || $response == "N" ]]; then
        return 1;
    fi
    return 1;

}


prompt_enter(){
    local answer;
    prompt "$1 [enter to continue]" response
    if [[ $response == "" ]]; then
        return 0;
    fi
    return 1;
}

prompt_yesnotwo(){
    local answer;
    prompt "$1 (y-yes/n-no): " response
    yesFunc=$2;
    noFunc=$3;
    if [[ $response == "y" || $response == "Y" ]]; then
        return 0
    elif [[ $response == "n" || $response == "N" ]]; then
        return 1;
    fi
    return 1;
}

prompt_yesno(){
    local answer;
    prompt "$1 (y-yes/n-no): " response
    yesFunc=$2;
    noFunc=$3;
    if [[ $response == "y" || $response == "Y" ]]; then
        answer=0;
        if [[ -n "$yesFunc" ]]; then
            $yesFunc
        fi
    elif [[ $response == "n" || $response == "N" ]]; then
        answer=1;
        if [[ -n "$noFunc" ]]; then
            $noFunc
        fi
    fi
    return $answer;
}


prompt_yesno_bool(){
    local answer;
    prompt "$1 (y-yes/n-no): " response
    local -n answer=${2}
    if [[ $response == "y" || $response == "Y" ]]; then
        answer=true;
    elif [[ $response == "n" || $response == "N" ]]; then
        answer=false;
    fi
    
}

# To print the answer and return when quit, use [prompt_exited "$response" -p && return;]
# To simply return in your function without printing anything: [prompt_exited "$response" && return;]
# @TODO add flag for using empty as a cancel as well
prompt_exited(){
	# @TODO add option to accept empty string (or possibly other "quit" responses
    if [[ "$2" == "-p" ]]; then
        shouldPrint=true;
    else
        shouldPrint=false;
    fi;
    case "$1" in
        n|N)
            $shouldPrint && msg_status "answered no"
            return 0
        ;;
        q|Q)
            $shouldPrint && msg_status "quitting"
            return 0
        ;;
        c|C)
            $shouldPrint && msg_status "canceled"
            return 0
        ;;
        "")
            $shouldPrint && msg_status "needed answer"
            return 0
        ;;
    esac
    return 1;
}

function prompt_choose_function(){
    prompt_choose cmd "$@" \
        && $cmd
}

# Use like:
#  prompt_choose choice 
#      "# header" \
#      "'message" \
#      "choice_1" "shorthand" "choice 1 description" \
#      "choice_2" "shorthand 2" "choice 2 description" \
#  ;
#  echo "${choice}"
#
#  prompt_choose returns true if choice successful, false otherwise. 
#  Allows usage like:
#  prompt_choose cmd ... && $cmd;
#  To choose a command from the list & execute it OR do nothing
#
#  Shorthands are optional. If omitting, use empty string: "choice" "" "description"
function prompt_choose(){
    ## INIT variables
    local -n output=$1
    output=""
    declare -a functions;
    # To make it a base-1 array
    functions+=("")
    declare -A shorthands;

    entryCount=0
    shorthandCount=0

    status=$open
    stOpen=0
    stFunction=1
    stShorthand=2

    # Print entries & headers
    for str in "${@:2}"; do
        charOne=${str:0:1}
        if [[ $status -eq $stOpen && ${charOne} == "#" ]]; then
            # display header
            msg
            header "${str:1}"
        elif [[ $status -eq $stOpen && ${charOne} == "'" ]]; then
            # display header
            msg "  ${str:1}"
        elif [[ $status -eq $stOpen ]]; then
            # store functions
            entryCount=$(($entryCount + 1))
            functions+=("${str}")
            status=$stFunction
        elif [[ $status -eq $stFunction ]]; then
            # store shorthands
            if [[ -z "$str" ]];then
                has_shorthand=false
            else
                has_shorthand=true
                prevShorthand="$str"
                shorthandCount+=1;
                shorthands["$str"]="$entryCount"
            fi
            status=$stShorthand
        elif [[ $status -eq $stShorthand ]]; then
            # display entry
            shStr=""
            if $has_shorthand;then
                d=$(($entryCount + 1))
                shStr="$(color_li $d)[$prevShorthand]${cOff} "
            fi
            msg "  $(color_li $entryCount)${entryCount}.${cOff} ${shStr}${str}"
            status=$stOpen
        fi
    done


    has_shorthand=false;
    if [[ $shorthandCount -gt 0 ]];then
        has_shorthand=true
    fi
    
    # prompt for choice
    msg
    msg_instruct "(q-quit)"
    $has_shorthand \
        && prompt "Type the [shorthand]\n or choose (1-${entryCount}):" answer \
        || prompt "Choose (1-${entryCount}):" answer
    prompt_exited "$answer" -p && return 1;

    # Determine function from answer
    funcIndex="${shorthands[${answer}]}"
    if [[ -z "$funcIndex" ]]; then
        funcIndex="$answer"
    fi
    func="${functions[${funcIndex}]}"

    # Display wrong answer message
    if [[ -z "${func}" ]];then
        shMsg=""
        if $has_shorthand;then
            shMsg="\n   OR a [shorthand] (without the brackets)"
        fi
        msg_mistake "A number 1-${entryCount}${shMsg} is required.\nYou entered " \
            "${num}" \
        ;
        return 1;
    fi;

    # set output & return true
    output="${func}"
    return 0;
}